想要回去GET请求中的请求参数,可以直接使用request.getParamMap()方法。但是POST请求的requestBody参数就必须使用流的方式来获取。
BufferedReader reader = null;
String body = null;
try {
reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
body = IOUtils.read(reader).replaceAll("\t|\n|\r", "");
} catch (IOException e) {
logger.error("流读取错误:"+e);
return;
}finally {
if (null != reader){
try {
reader.close();
} catch (IOException e) {
logger.error("流关闭错误:"+e);
}
}
}
Map<String,Object> paramMap = JSON.parseObject(body);
这样将获取body中的所有json格式的参数信息。可以根据需求,进行验签或校验等一系列操作。但是当我们chain.doFilter(request, response),惊喜的发现接口400了!!
WHAT??!!
嘿嘿o( ̄▽ ̄)d
我们都知道,读取流的时候是有标志的,读取一次移动一次,读取到哪里,移动到哪里,读到最后,返回-1,表示读取完成。再次读取需要重置位置,但是ServletInputStream中是没有重置方法的,也就是说流只能被读取一次。神奇!!Σ(⊙▽⊙"a 此时的流已经被读取一次,相当于已经作废,此时请求接口必然是报错的。
行吧,你既然不让我重复读,那我就把你的流拿过来封装成自己的流,这样我想读多少次就读多少次!ψ(`∇´)ψ
加入jar包:javax.servlet
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
实现HttpServletRequestWrapper类
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.net.URLDecoder;
import java.util.*;
/**
* @author zhoumin
* @create 2018-10-31 16:13
*/
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private Map<String, String[]> paramsMap;
@Override
public Map getParameterMap() {
return paramsMap;
}
@Override
public String getParameter(String name) {// 重写getParameter,代表参数从当前类中的map获取
String[] values = paramsMap.get(name);
if (values == null || values.length == 0) {
return null;
}
return values[0];
}
@Override
public String[] getParameterValues(String name) {// 同上
return paramsMap.get(name);
}
@Override
public Enumeration getParameterNames() {
return Collections.enumeration(paramsMap.keySet());
}
private String getRequestBody(InputStream stream) {
String line = "";
StringBuilder body = new StringBuilder();
int counter = 0;
// 读取POST提交的数据内容
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
try {
while ((line = reader.readLine()) != null) {
if (counter > 0) {
body.append("rn");
}
body.append(line);
counter++;
}
} catch (IOException e) {
e.printStackTrace();
}
return body.toString();
}
private HashMap<String, String[]> getParamMapFromPost(HttpServletRequest request) {
String body = "";
try {
body = getRequestBody(request.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
HashMap<String, String[]> result = new HashMap<String, String[]>();
if (null == body || 0 == body.length()) {
return result;
}
return parseQueryString(body);
}
// 自定义解码函数
private String decodeValue(String value) {
if (value.contains("%u")) {
return Encodes.urlDecode(value);
} else {
try {
return URLDecoder.decode(value, "UTF-8");
} catch (UnsupportedEncodingException e) {
return "";// 非UTF-8编码
}
}
}
public HashMap<String, String[]> parseQueryString(String s) {
String valArray[] = null;
if (s == null) {
throw new IllegalArgumentException();
}
HashMap<String, String[]> ht = new HashMap<String, String[]>();
StringTokenizer st = new StringTokenizer(s, "&");
while (st.hasMoreTokens()) {
String pair = (String) st.nextToken();
int pos = pair.indexOf('=');
if (pos == -1) {
continue;
}
String key = pair.substring(0, pos);
String val = pair.substring(pos + 1, pair.length());
if (ht.containsKey(key)) {
String oldVals[] = (String[]) ht.get(key);
valArray = new String[oldVals.length + 1];
for (int i = 0; i < oldVals.length; i++) {
valArray[i] = oldVals[i];
}
valArray[oldVals.length] = decodeValue(val);
} else {
valArray = new String[1];
valArray[0] = decodeValue(val);
}
ht.put(key, valArray);
}
return ht;
}
private Map<String, String[]> getParamMapFromGet(HttpServletRequest request) {
return parseQueryString(request.getQueryString());
}
private final byte[] body; // 报文
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
body = readBytes(request.getInputStream());
// 首先从POST中获取数据
if ("POST".equals(request.getMethod().toUpperCase())) {
paramsMap = getParamMapFromPost(this);
} else {
paramsMap = getParamMapFromGet(this);
}
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener arg0) {
}
};
}
private static byte[] readBytes(InputStream in) throws IOException {
BufferedInputStream bufin = new BufferedInputStream(in);
int buffSize = 1024;
ByteArrayOutputStream out = new ByteArrayOutputStream(buffSize);
byte[] temp = new byte[buffSize];
int size = 0;
while ((size = bufin.read(temp)) != -1) {
out.write(temp, 0, size);
}
bufin.close();
byte[] content = out.toByteArray();
return content;
}
}
解码
/**
* URL 解码, Encode默认为UTF-8.
*/
public static String urlDecode(String part) {
try {
return URLDecoder.decode(part, DEFAULT_URL_ENCODING);
} catch (UnsupportedEncodingException e) {
throw new InvalidTokenException(part);
}
}
那么上面读取参数的代码修改为:
ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(
(HttpServletRequest) request);
BufferedReader reader = null;
String body = null;
try {
reader = new BufferedReader(new InputStreamReader(requestWrapper.getInputStream()));
body = IOUtils.read(reader).replaceAll("\t|\n|\r", "");
} catch (IOException e) {
logger.error("流读取错误:"+e);
return;
}finally {
if (null != reader){
try {
reader.close();
} catch (IOException e) {
logger.error("流关闭错误:"+e);
}
}
}
Map<String,Object> paramMap = JSON.parseObject(body);
.
.
.
chain.doFilter(requestWrapper, response);
OK!又是打酱油的一天。(づ。◕ᴗᴗ◕。)づ
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。